﻿
#region Usings
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Reflection;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
#endregion

namespace FasterWPF
{
    public class ValueChangedEventArgs : EventArgs
    {
        private object _newValue;
        private object _oldValue;

        public ValueChangedEventArgs(object oldValue, object newValue)
        {
            this._oldValue = oldValue;
            this._newValue = newValue;
        }

        public object NewValue
        {
            get
            {
                return this._newValue;
            }
        }

        public object OldValue
        {
            get
            {
                return this._oldValue;
            }
        }
    }

    public class DependencyEventListener
    {
        private FrameworkElement _targetElement;
        private DependencyPropertyChangedEventHandler dceh;
        public event EventHandler<ValueChangedEventArgs> ValueChanged;

        public FrameworkElement SenderElement
        { 
            get{return _targetElement;}
        }

        public DependencyEventListener(FrameworkElement targetElement)
        {
            _targetElement = targetElement;
        }

        public void SubscribeEvent(EventInfo evInfo)
        {
            EventHandler<ValueChangedEventArgs> handler = this.ValueChanged;

            dceh = new DependencyPropertyChangedEventHandler((o,e)=>{

                if (handler != null)
                {
                    handler(o, new ValueChangedEventArgs(e.OldValue, e.NewValue));
                }          
  
            });
            evInfo.AddEventHandler(_targetElement, dceh);            
        }

        public void UnsubscribeEvent(EventInfo evInfo)
        {
            evInfo.RemoveEventHandler(_targetElement, dceh);

            dceh = null;
            _targetElement = null;
            ValueChanged = null;
        }
    }

    public static partial class CommonExt
    {
        #region Subscribe, Dispose, Unsubscribe, Get Delegates

        #region BeginComposite . . . EndComposite

        /// <summary>
        /// Subscribe PreviewMouseDown Event with ClickCount of 2 on Child K. Call within BeginComposite...EndComposite chain.
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <param name="delegAction"></param>
        /// <returns></returns>
        public static InnerChain<T> SubscribeMouseDoubleClickOnChild<K, T>(this InnerChain<T> chain, int row, int column, Action<Object, MouseButtonEventArgs> delegAction)
            where T : FrameworkElement
            where K : FrameworkElement
        {
            Action<EventPattern<MouseButtonEventArgs>> indirectAction =  eventPattern =>
                    {
                        if (delegAction != null)
                        {
                            if (eventPattern.EventArgs.ClickCount == 2)
                            {
                                delegAction(eventPattern.Sender, eventPattern.EventArgs);
                            }
                        }
                    };

            chain.Item3.Add(((container) =>
            {
                return container.SubscribeEventOnChild<K, T, MouseButtonEventArgs>(chain.Item2, row, column, "PreviewMouseDown", indirectAction);
            }));

            return chain;
        }

        /// <summary>
        /// Subscribe PreviewMouseDown Event with ClickCount of 1 on Child K. Call within BeginComposite...EndComposite chain.
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <param name="delegAction"></param>
        /// <returns></returns>
        public static InnerChain<T> SubscribeMouseSingleClickOnChild<K, T>(this InnerChain<T> chain, int row, int column, Action<Object, MouseButtonEventArgs> actionDelegate)
            where T : FrameworkElement
            where K : FrameworkElement
        {
            Action<EventPattern<MouseButtonEventArgs>> indirectAction =  eventPattern =>
                {
                    if (actionDelegate != null)
                    {
                        if (eventPattern.EventArgs.ClickCount == 1)
                        {
                            actionDelegate(eventPattern.Sender, eventPattern.EventArgs);
                        }
                    }
                };

            chain.Item3.Add(((container) =>
            {
                return container.SubscribeEventOnChild<K, T, MouseButtonEventArgs>(chain.Item2, row, column, "PreviewMouseDown", indirectAction);
            }));

            return chain;
        }

        /// <summary>
        /// Subscribe PreviewMouseDown Event with ClickCount of 1 on Composite Container. Call within BeginComposite...EndComposite chain.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="eventName"></param>
        /// <param name="deleg"></param>
        /// <returns></returns>
        public static InnerChain<T> SubscribeMouseSingleClickOnContainer<C, T>(this InnerChain<T> chain, Action<object, MouseButtonEventArgs> delegAction)
            where C : FrameworkElement
            where T : FrameworkElement
        {
            chain.Item3.Add(((container) =>
            {
                return container.SubscribeEventOnContainer<C, T, MouseButtonEventArgs>(chain.Item2, "PreviewMouseDown", ((ev) =>
                {
                    if (delegAction != null)
                    {
                        if (ev.EventArgs.ClickCount == 1)
                        {
                            delegAction(ev.Sender, ev.EventArgs);
                        }
                    }
                }));
            }));
            return chain;
        }

        /// <summary>
        /// Subscribe PreviewMouseDown Event with ClickCount of 1 on Composite Container. Call within BeginComposite...EndComposite chain.
        /// </summary>
        /// <typeparam name="C"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="delegAction"></param>
        /// <param name="shouldSubscribe"></param>
        /// <returns></returns>
        public static InnerChain<T> SubscribeMouseSingleClickOnContainer<C, T>(this InnerChain<T> chain, Action<object, MouseButtonEventArgs> delegAction, Predicate<C> shouldSubscribe)
            where C : FrameworkElement
            where T : FrameworkElement
        {
            chain.Item3.Add(((container) =>
            {
                return container.SubscribeEventOnContainer<C, T, MouseButtonEventArgs>(chain.Item2, "PreviewMouseDown", ((ev) =>
                {
                    if (delegAction != null)
                    {
                        if (ev.EventArgs.ClickCount == 1)
                        {
                            delegAction(ev.Sender, ev.EventArgs);
                        }
                    }
                }), shouldSubscribe);
            }));
            return chain;
        }

        /// <summary>
        ///  Subscribe PreviewMouseDown Event with ClickCount of 2 on Composite Container. Call within BeginComposite...EndComposite chain.
        /// </summary>
        /// <typeparam name="C"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="delegAction"></param>
        /// <returns></returns>
        public static InnerChain<T> SubscribeMouseDoubleClickOnContainer<C, T>(this InnerChain<T> chain, Action<object, MouseButtonEventArgs> delegAction)
            where C : FrameworkElement
            where T : FrameworkElement
        {
            chain.Item3.Add(((container) =>
            {
                return container.SubscribeEventOnContainer<C, T, MouseButtonEventArgs>(chain.Item2, "PreviewMouseDown", ((ev) =>
                {
                    if (delegAction != null)
                    {
                        if (ev.EventArgs.ClickCount == 2)
                        {
                            delegAction(ev.Sender, ev.EventArgs);
                        }
                    }
                }));
            }));
            return chain;
        }

        /// <summary>
        /// Subscribe PreviewMouseDown Event with ClickCount of 2 on Composite Container. Call within BeginComposite...EndComposite chain.
        /// </summary>
        /// <typeparam name="C"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="delegAction"></param>
        /// <param name="shouldSubscribe"></param>
        /// <returns></returns>
        public static InnerChain<T> SubscribeMouseDoubleClickOnContainer<C, T>(this InnerChain<T> chain, Action<object, MouseButtonEventArgs> delegAction, Predicate<C> shouldSubscribe)
            where C : FrameworkElement
            where T : FrameworkElement
        {
            chain.Item3.Add(((container) =>
            {
                return container.SubscribeEventOnContainer<C, T, MouseButtonEventArgs>(chain.Item2, "PreviewMouseDown", ((ev) =>
                {
                    if (delegAction != null)
                    {
                        if (ev.EventArgs.ClickCount == 2)
                        {
                            delegAction(ev.Sender, ev.EventArgs);
                        }
                    }
                }), shouldSubscribe);
            }));
            return chain;
        }

        /// <summary>
        /// Subscribe PreviewMouseDown Event with ClickCount of 1 on Parent T.
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <param name="delegAction"></param>
        /// <returns></returns>
        public static T SubscribeMouseSingleClickOnParent<T>(this T chain, Action<object, MouseButtonEventArgs> delegAction)
            where T : FrameworkElement
        {
            return chain.SubscribeEventOnParent<T, MouseButtonEventArgs>("PreviewMouseDown", ((ev) =>
            {
                if (delegAction != null)
                {
                    if (ev.EventArgs.ClickCount == 1)
                    {
                        delegAction(ev.Sender, ev.EventArgs);
                    }
                }
            }));
        }

        /// <summary>
        /// Subscribe PreviewMouseDown Event with ClickCount of 1 on Parent T filtering by a Predicate.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="delegAction"></param>
        /// <param name="shouldSubscribe"></param>
        /// <returns></returns>
        public static T SubscribeMouseSingleClickOnParent<T>(this T chain, Action<object, MouseButtonEventArgs> delegAction, Predicate<T> shouldSubscribe)
            where T : FrameworkElement
        {
            return chain.SubscribeEventOnParent<T, MouseButtonEventArgs>("PreviewMouseDown", ((ev) =>
            {
                if (delegAction != null)
                {
                    if (ev.EventArgs.ClickCount == 1)
                    {
                        delegAction(ev.Sender, ev.EventArgs);
                    }
                }
            }), shouldSubscribe);
        }

        /// <summary>
        /// Subscribe PreviewMouseDown Event with ClickCount of 2 on Parent T.
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <param name="delegAction"></param>
        /// <returns></returns>
        public static T SubscribeMouseDoubleClickOnParent<T>(this T chain, Action<object, MouseButtonEventArgs> delegAction)
            where T : FrameworkElement
        {
            return chain.SubscribeEventOnParent<T, MouseButtonEventArgs>("PreviewMouseDown", ((ev) =>
            {
                if (delegAction != null)
                {
                    if (ev.EventArgs.ClickCount == 2)
                    {
                        delegAction(ev.Sender, ev.EventArgs);
                    }
                }
            }));
        }

        /// <summary>
        /// Subscribe PreviewMouseDown Event with ClickCount of 2 on Parent T filtering by a Predicate.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="delegAction"></param>
        /// <param name="shouldSubscribe"></param>
        /// <returns></returns>
        public static T SubscribeMouseDoubleClickOnParent<T>(this T chain, Action<object, MouseButtonEventArgs> delegAction, Predicate<T> shouldSubscribe)
            where T : FrameworkElement
        {
            return chain.SubscribeEventOnParent<T, MouseButtonEventArgs>("PreviewMouseDown", ((ev) =>
            {
                if (delegAction != null)
                {
                    if (ev.EventArgs.ClickCount == 2)
                    {
                        delegAction(ev.Sender, ev.EventArgs);
                    }
                }
            }), shouldSubscribe);
        }

        /// <summary>
        /// Subscribe Event on Child K. Call within BeginComposite...EndComposite chain.
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="key"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <param name="eventName"></param>
        /// <param name="deleg"></param>
        /// <returns></returns>
        public static InnerChain<T> SubscribeEventOnChild<K, T, TEventArgs>(this InnerChain<T> chain, int row, int column, string eventName, Action<Object, TEventArgs> deleg)
            where T : FrameworkElement
            where K : FrameworkElement
            where TEventArgs : EventArgs
        {
            Action<EventPattern<TEventArgs>> indirectAction = eventPattern =>
            {
                if (deleg != null)
                {
                    deleg(eventPattern.Sender, eventPattern.EventArgs);
                }
            };

            chain.Item3.Add(((container) =>
            {
                return container.SubscribeEventOnChild<K, T, TEventArgs>(chain.Item2, row, column, eventName, indirectAction);
            }));

            return chain;
        }

        /// <summary>
        /// Subscribe Event on Child K. Call within BeginComposite...EndComposite chain.
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="key"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <param name="eventName"></param>
        /// <param name="deleg"></param>
        /// <returns></returns>
        public static InnerChain<T> SubscribeEventOnChild<K, T, TEventArgs>(this InnerChain<T> chain, int row, int column, string eventName, Action<Object, TEventArgs> deleg, Action<IConnectableObservable<EventPattern<TEventArgs>>, Action<EventPattern<TEventArgs>>> composeObservable)
            where T : FrameworkElement
            where K : FrameworkElement
            where TEventArgs : EventArgs
        {
            Action<EventPattern<TEventArgs>> indirectAction = eventPattern =>
            {
                if (deleg != null)
                {
                    deleg(eventPattern.Sender, eventPattern.EventArgs);
                }
            };

            chain.Item3.Add(((container) =>
            {
                return container.SubscribeEventOnChild<K, T, TEventArgs>(chain.Item2, row, column, eventName, indirectAction, composeObservable);
            }));

            return chain;
        }

        /// <summary>
        /// Subscribe Dependency Property Event on Child K. Call within BeginComposite...EndComposite chain.
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="key"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <param name="eventName"></param>
        /// <param name="deleg"></param>
        /// <returns></returns>
        public static InnerChain<T> SubscribeDependencyEventOnChild<K, T>(this InnerChain<T> chain, int row, int column, string eventName, Action<Object, ValueChangedEventArgs> actionDelegate, Action<IConnectableObservable<EventPattern<ValueChangedEventArgs>>, Action<EventPattern<ValueChangedEventArgs>>> composeObservable)
            where T : FrameworkElement
            where K : FrameworkElement
        {
            Action<EventPattern<ValueChangedEventArgs>> indirectAction = eventPattern =>
            {
                if (actionDelegate != null)
                {
                    actionDelegate(eventPattern.Sender, eventPattern.EventArgs);
                }
            };

            chain.Item3.Add(((container) =>
            {
                return container.SubscribeDependencyEventOnChild<K, T>(chain.Item2, row, column, eventName, indirectAction, composeObservable);
            }));

            return chain;
        }

        /// <summary>
        /// Subscribe Dependency Property Event on Child K. Call within BeginComposite...EndComposite chain.
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="key"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <param name="eventName"></param>
        /// <param name="deleg"></param>
        /// <returns></returns>
        public static InnerChain<T> SubscribeDependencyEventOnChild<K, T>(this InnerChain<T> chain, int row, int column, string eventName, Action<Object, ValueChangedEventArgs> actionDelegate)
            where T : FrameworkElement
            where K : FrameworkElement
        {
            Action<EventPattern<ValueChangedEventArgs>> indirectAction = eventPattern =>
            {
                if (actionDelegate != null)
                {
                    actionDelegate(eventPattern.Sender, eventPattern.EventArgs);
                }
            };

            chain.Item3.Add(((container) =>
            {
                return container.SubscribeDependencyEventOnChild<K, T>(chain.Item2, row, column, eventName, indirectAction);
            }));

            return chain;
        }

        /// <summary>
        /// Subscribe Dependency Property Event on Child K filtering by a Predicate. Call within BeginComposite...EndComposite chain.
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <param name="eventName"></param>
        /// <param name="deleg"></param>
        /// <returns></returns>
        public static InnerChain<T> SubscribeDependencyEventOnChild<K, T>(this InnerChain<T> chain, int row, int column, string eventName, Action<Object, ValueChangedEventArgs> actionDelegate, Predicate<K> shouldSubscribe)
            where T : FrameworkElement
            where K : FrameworkElement
        {
            Action<EventPattern<ValueChangedEventArgs>> indirectAction = eventPattern =>
            {
                if (actionDelegate != null)
                {
                    actionDelegate(eventPattern.Sender, eventPattern.EventArgs);
                }
            };

            chain.Item3.Add(((container) =>
            {
                return container.SubscribeDependencyEventOnChild<K, T>(chain.Item2, row, column, eventName, indirectAction, shouldSubscribe);
            }));

            return chain;
        }

        /// <summary>
        /// Subscribe Event on Child K filtering by a Predicate. Call within BeginComposite...EndComposite chain.
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <param name="eventName"></param>
        /// <param name="deleg"></param>
        /// <returns></returns>
        public static InnerChain<T> SubscribeEventOnChild<K, T, TEventArgs>(this InnerChain<T> chain, int row, int column, string eventName,  Action<Object, TEventArgs> deleg, Predicate<K> shouldSubscribe)
            where T : FrameworkElement
            where K : FrameworkElement
            where TEventArgs : EventArgs
        {
            Action<EventPattern<TEventArgs>> indirectAction = eventPattern =>
            {
                if (deleg != null)
                {
                    deleg(eventPattern.Sender, eventPattern.EventArgs);
                }
            };

            chain.Item3.Add(((container) =>
            {
                return container.SubscribeEventOnChild<K, T, TEventArgs>(chain.Item2, row, column, eventName, indirectAction, shouldSubscribe);
            }));

            return chain;
        }

        /// <summary>
        /// Subscribe Event on Parent. Call within BeginSettings...EndSettings chain.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="eventName"></param>
        /// <param name="deleg"></param>
        /// <returns></returns>
        public static SettingsChain<T> SubscribeEventOnParent<T, TEventArgs>(this SettingsChain<T> chain, string eventName, Action<Object, TEventArgs> delegAction)
            where T : FrameworkElement
            where TEventArgs : EventArgs
        {
            Action<EventPattern<TEventArgs>> indirectAction = eventPattern =>
            {
                if (delegAction != null)
                {
                    delegAction(eventPattern.Sender, eventPattern.EventArgs);
                }
            };

            Predicate<T> shouldSubscribe = item => { return true; };

            chain.Item1.SubscribeEventOnParent<T, TEventArgs>(eventName, indirectAction, shouldSubscribe);

            return chain;
        }

        /// <summary>
        /// Subscribe Dependency Property Event on Parent. Call within BeginSettings...EndSettings chain.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="eventName"></param>
        /// <param name="deleg"></param>
        /// <returns></returns>
        public static SettingsChain<T> SubscribeDependencyEventOnParent<T>(this SettingsChain<T> chain, string eventName, Action<EventPattern<ValueChangedEventArgs>> delegAction)
            where T : FrameworkElement
        {
            Action<EventPattern<ValueChangedEventArgs>> indirectAction = eventPattern =>
            {
                if (delegAction != null)
                {
                    delegAction(eventPattern);
                }
            };

            Predicate<T> shouldSubscribe = item => { return true; };

            chain.Item1.SubscribeDependencyEventOnParent<T>(eventName, indirectAction, shouldSubscribe);

            return chain;
        }

        /// <summary>
        /// Subscribe Dependency Property Event on Parent with Predicate. Call within BeginSettings...EndSettings chain.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="eventName"></param>
        /// <param name="deleg"></param>
        /// <returns></returns>
        public static SettingsChain<T> SubscribeDependencyEventOnParent<T>(this SettingsChain<T> chain, string eventName, Action<EventPattern<ValueChangedEventArgs>> delegAction, Predicate<T> shouldSubscribe)
            where T : FrameworkElement
        {
            Action<EventPattern<ValueChangedEventArgs>> indirectAction = eventPattern =>
            {
                if (delegAction != null)
                {
                    delegAction(eventPattern);
                }
            };

            chain.Item1.SubscribeDependencyEventOnParent<T>(eventName, indirectAction, shouldSubscribe);

            return chain;
        }


        /// <summary>
        /// Subscribe selection changed on a Parent. NOT meant to be used with child objects. Sets only one and only once. Call within BeginSettings...EndSettings chain.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="delegAction"></param>
        /// <returns></returns>
        public static SettingsChain<T> SubscribeSelectionChangedOnParent<T>(this SettingsChain<T> chain, Action<object, SelectionChangedEventArgs> delegAction)
             where T : FrameworkElement
        {
            chain.Item1.SubscribeSelectionChangedOnParent<T>(delegAction);
            return chain;
        }

        /// <summary>
        /// Conditionally subscribe selection changed on a Parent. NOT meant to be used with child objects. Sets only one and only once. Call within BeginSettings...EndSettings chain.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="delegAction"></param>
        /// <returns></returns>
        public static SettingsChain<T> SubscribeSelectionChangedOnParent<T>(this SettingsChain<T> chain, Action<object, SelectionChangedEventArgs> delegAction, Predicate<T> shouldSubscribe)
       where T : FrameworkElement
        {
            chain.Item1.SubscribeSelectionChangedOnParent<T>(delegAction, shouldSubscribe);
            return chain;
        }

        /// <summary>
        /// Subscribe PreviewMouseLeftButtonDown on Composite (Border). Call within BeginSettings...EndSettings chain.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="delegAction"></param>
        /// <returns></returns>
        public static SettingsChain<T> SubscribeMouseSingleClickOnBorder<T>(this SettingsChain<T> chain, Action<object, MouseButtonEventArgs> delegAction)
              where T : FrameworkElement
        {
            chain.Item1.SubscribeMouseSingleClickOnBorder<T>(delegAction);
            return chain;
        }

        /// <summary>
        /// Conditionally subscribe PreviewMouseLeftButtonDown on Composite (Border). Call within BeginSettings...EndSettings chain.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="delegAction"></param>
        /// <param name="shouldSubscribe"></param>
        /// <returns></returns>
        public static SettingsChain<T> SubscribeMouseSingleClickOnBorder<T>(this SettingsChain<T> chain, Action<object, MouseButtonEventArgs> delegAction, Predicate<Border> shouldSubscribe)
where T : FrameworkElement
        {
            chain.Item1.SubscribeMouseSingleClickOnBorder<T>(delegAction, shouldSubscribe);
            return chain;
        }

        /// <summary>
        /// Subscribe PreviewMouseLeftButtonDown with ClickCount of 2 on Composite (Border). Call within BeginSettings...EndSettings chain.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="deleg"></param>
        /// <returns></returns>
        public static SettingsChain<T> SubscribeMouseDoubleClickOnBorder<T>(this SettingsChain<T> chain, Action<object, MouseButtonEventArgs> delegAction)
                      where T : FrameworkElement
        {
            chain.Item1.SubscribeMouseDoubleClickOnBorder<T>(delegAction);
            return chain;
        }

        /// <summary>
        /// Conditionally subscribe PreviewMouseLeftButtonDown with ClickCount of 2 on Composite (Border). Call within BeginSettings...EndSettings chain.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="delegAction"></param>
        /// <param name="shouldSubscribe"></param>
        /// <returns></returns>
        public static SettingsChain<T> SubscribeMouseDoubleClickOnBorder<T>(this SettingsChain<T> chain, Action<object, MouseButtonEventArgs> delegAction, Predicate<Border> shouldSubscribe)
               where T : FrameworkElement
        {
            chain.Item1.SubscribeMouseDoubleClickOnBorder<T>(delegAction, shouldSubscribe);
            return chain;
        }

        /// <summary>
        /// Conditionally subscribe Event on Parent. Call within BeginSettings...EndSettings chain.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="eventName"></param>
        /// <param name="deleg"></param>
        /// <param name="shouldSubscribe"></param>
        /// <returns></returns>
        public static SettingsChain<T> SubscribeEventOnParent<T, TEventArgs>(this SettingsChain<T> chain, string eventName, Action<object, TEventArgs> delegAction, Predicate<T> shouldSubscribe)
            where T : FrameworkElement
            where TEventArgs: EventArgs
        {
            Action<EventPattern<TEventArgs>> indirectAction = eventPattern =>
            {
                if (delegAction != null)
                {
                    delegAction(eventPattern.Sender, eventPattern.EventArgs);
                }
            };

            chain.Item1.SubscribeEventOnParent<T, TEventArgs>(eventName, indirectAction, shouldSubscribe);

            return chain;
        }

        /// <summary>
        /// Subscribe PreviewMouseLeftButtonDown on Composite (Border) [from but not on child element]. This is for subscribing on-the-fly; e.g., if an element were unsubscribed and needs re-subscribing. Call within BeginComposite...EndComposite chain.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="childElement"></param>
        /// <returns></returns>
        public static InnerChain<T> SubscribeMouseSingleClickOnBorder<T>(this InnerChain<T> chain, FrameworkElement childElement)
             where T : FrameworkElement
        {
            chain.Item1.SubscribeMouseSingleClickOnBorder<T>(childElement);
            return chain;
        }

        /// <summary>
        /// Subscribe PreviewMouseLeftButtonDown with ClickCount of 2 on Composite (Border) [from but not on child element]. This is for subscribing on-the-fly; e.g., if an element were unsubscribed and needs re-subscribing. Call within BeginComposite...EndComposite chain.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="childElement"></param>
        /// <returns></returns>
        public static InnerChain<T> SubscribeMouseDoubleClickOnBorder<T>(this InnerChain<T> chain, FrameworkElement childElement)
             where T : FrameworkElement
        {
            chain.Item1.SubscribeMouseDoubleClickOnBorder<T>(childElement);
            return chain;
        }

        /// <summary>
        /// Subscribe any event by key on Composite Container. Call within BeginComposite...EndComposite chain.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="eventName"></param>
        /// <param name="deleg"></param>
        /// <returns></returns>
        public static InnerChain<T> SubscribeEventOnContainer<C, T, TEventArgs>(this InnerChain<T> chain, string eventName, Action<object, TEventArgs> actionDelegate)
            where C : FrameworkElement
            where T : FrameworkElement
            where TEventArgs: EventArgs
        {
            Action<EventPattern<TEventArgs>> indirectAction = eventPattern =>
            {
                if (actionDelegate != null)
                {
                    actionDelegate(eventPattern.Sender, eventPattern.EventArgs);
                }
            };

            chain.Item3.Add(((container) =>
            {
                return container.SubscribeEventOnContainer<C, T, TEventArgs>(chain.Item2, eventName, indirectAction);
            }));
            return chain;
        }

        /// <summary>
        /// Conditionally subscribe any event by key on Composite Container. Call within BeginComposite...EndComposite chain.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="eventName"></param>
        /// <param name="deleg"></param>
        /// <returns></returns>
        public static InnerChain<T> SubscribeEventOnContainer<C, T, TEventArgs>(this InnerChain<T> chain, string eventName, Action<object, TEventArgs> actionDelegate, Predicate<C> shouldSubscribe)
            where C : FrameworkElement
            where T : FrameworkElement
            where TEventArgs : EventArgs
        {
            Action<EventPattern<TEventArgs>> indirectAction = eventPattern =>
            {
                if (actionDelegate != null)
                {
                    actionDelegate(eventPattern.Sender, eventPattern.EventArgs);
                }
            };

            chain.Item3.Add(((container) =>
            {
                return container.SubscribeEventOnContainer<C, T, TEventArgs>(chain.Item2, eventName, indirectAction, shouldSubscribe);
            }));

            return chain;
        }


        /// <summary>
        /// Subscribe any Dependency Property event by key on Composite Container. Call within BeginComposite...EndComposite chain.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="eventName"></param>
        /// <param name="deleg"></param>
        /// <returns></returns>
        public static InnerChain<T> SubscribeDependencyEventOnContainer<C, T>(this InnerChain<T> chain, string eventName, Action<object, ValueChangedEventArgs> actionDelegate)
            where C : FrameworkElement
            where T : FrameworkElement
        {
            Action<EventPattern<ValueChangedEventArgs>> indirectAction = eventPattern =>
            {
                if (actionDelegate != null)
                {
                    actionDelegate(eventPattern.Sender, eventPattern.EventArgs);
                }
            };

            chain.Item3.Add(((container) =>
            {
                return container.SubscribeDependencyEventOnContainer<C, T>(chain.Item2, eventName, indirectAction);
            }));
            return chain;
        }

        /// <summary>
        /// Conditionally subscribe any Dependency Property event by key on Composite Container. Call within BeginComposite...EndComposite chain.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="eventName"></param>
        /// <param name="deleg"></param>
        /// <returns></returns>
        public static InnerChain<T> SubscribeDependencyEventOnContainer<C, T>(this InnerChain<T> chain, string eventName, Action<object, ValueChangedEventArgs> actionDelegate, Predicate<C> shouldSubscribe)
            where C : FrameworkElement
            where T : FrameworkElement
        {
            Action<EventPattern<ValueChangedEventArgs>> indirectAction = eventPattern =>
            {
                if (actionDelegate != null)
                {
                    actionDelegate(eventPattern.Sender, eventPattern.EventArgs);
                }
            };

            chain.Item3.Add(((container) =>
            {
                return container.SubscribeDependencyEventOnContainer<C, T>(chain.Item2, eventName, indirectAction, shouldSubscribe);
            }));

            return chain;
        }

        #endregion

        #region Subscribe

        /// <summary>
        /// Subscribe Event on Child. Call within AddComposite method.
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="key"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <param name="eventName"></param>
        /// <param name="deleg"></param>
        /// <returns></returns>
        public static ContentControl SubscribeEventOnChild<K, T, TEventArgs>(this ContentControl chain, string key, int row, int column, string eventName, Action<EventPattern<TEventArgs>> actionDelegate)
            where T : FrameworkElement
            where K : FrameworkElement
            where TEventArgs : EventArgs
        {
            T lbx = chain.GetTFromChildContentControl<T>();
            var dispDict = lbx.GetDisposablesDictionary<T>();
            var ChildLookupDict = lbx.GetChildLookupDictionary();
            string row_col = "_" + row + "_" + column;
            string fullKey = key + row_col;

            if (!dispDict.ContainsKey(eventName + row_col + key))
            {
                K kTemp = (K)ChildLookupDict[fullKey];
                Predicate<K> shouldSubscribe = item => { return true; };
                lbx.setAnyEventByKeyOnContainer<T, K, TEventArgs>(kTemp, eventName, row_col + key, actionDelegate, shouldSubscribe);
            }

            return chain;
        }

        /// <summary>
        /// Subscribe Event on Child. Call within AddComposite method.
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="key"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <param name="eventName"></param>
        /// <param name="deleg"></param>
        /// <returns></returns>
        public static ContentControl SubscribeEventOnChild<K, T, TEventArgs>(this ContentControl chain, string key, int row, int column, string eventName, Action<EventPattern<TEventArgs>> actionDelegate, Action<IConnectableObservable<EventPattern<TEventArgs>>, Action<EventPattern<TEventArgs>>> composeObservable)
            where T : FrameworkElement
            where K : FrameworkElement
            where TEventArgs : EventArgs
        {
            T lbx = chain.GetTFromChildContentControl<T>();
            var dispDict = lbx.GetDisposablesDictionary<T>();
            var ChildLookupDict = lbx.GetChildLookupDictionary();
            string row_col = "_" + row + "_" + column;
            string fullKey = key + row_col;

            if (!dispDict.ContainsKey(eventName + row_col + key))
            {
                K kTemp = (K)ChildLookupDict[fullKey];
                Predicate<K> shouldSubscribe = item => { return true; };
                lbx.setAnyEventByKeyOnContainer<T, K, TEventArgs>(kTemp, eventName, row_col + key, actionDelegate, shouldSubscribe, composeObservable);
            }

            return chain;
        }

        public static ContentControl SubscribeDependencyEventOnChild<K, T>(this ContentControl chain, string key, int row, int column, string eventName, Action<EventPattern<ValueChangedEventArgs>> actionDelegate, Action<IConnectableObservable<EventPattern<ValueChangedEventArgs>>, Action<EventPattern<ValueChangedEventArgs>>> composeObservable)
            where T : FrameworkElement
            where K : FrameworkElement
        {
            T lbx = chain.GetTFromChildContentControl<T>();
            var dispDict = lbx.GetDisposablesDictionary<T>();
            var ChildLookupDict = lbx.GetChildLookupDictionary();
            string row_col = "_" + row + "_" + column;
            string fullKey = key + row_col;

            if (!dispDict.ContainsKey(eventName + row_col + key))
            {
                K kTemp = (K)ChildLookupDict[fullKey];
                Predicate<K> shouldSubscribe = item => { return true; };
                lbx.setAnyDependencyEventByKeyOnContainer<T, K>(kTemp, eventName, row_col + key, actionDelegate, shouldSubscribe, composeObservable);
            }

            return chain;
        }

        public static ContentControl SubscribeDependencyEventOnChild<K, T>(this ContentControl chain, string key, int row, int column, string eventName, Action<EventPattern<ValueChangedEventArgs>> actionDelegate)
            where T : FrameworkElement
            where K : FrameworkElement
        {
            T lbx = chain.GetTFromChildContentControl<T>();
            var dispDict = lbx.GetDisposablesDictionary<T>();
            var ChildLookupDict = lbx.GetChildLookupDictionary();
            string row_col = "_" + row + "_" + column;
            string fullKey = key + row_col;

            if (!dispDict.ContainsKey(eventName + row_col + key))
            {
                K kTemp = (K)ChildLookupDict[fullKey];
                Predicate<K> shouldSubscribe = item => { return true; };
                lbx.setAnyDependencyEventByKeyOnContainer<T, K>(kTemp, eventName, row_col + key, actionDelegate, shouldSubscribe);
            }

            return chain;
        }

        public static ContentControl SubscribeDependencyEventOnChild<K, T>(this ContentControl chain, string key, int row, int column, string eventName, Action<EventPattern<ValueChangedEventArgs>> actionDelegate, Predicate<K> shouldSubscribe)
            where T : FrameworkElement
            where K : FrameworkElement
        {
            T lbx = chain.GetTFromChildContentControl<T>();
            var dispDict = lbx.GetDisposablesDictionary<T>();
            var ChildLookupDict = lbx.GetChildLookupDictionary();
            string row_col = "_" + row + "_" + column;
            string fullKey = key + row_col;

            if (!dispDict.ContainsKey(eventName + row_col + key))
            {
                K kTemp = (K)ChildLookupDict[fullKey];
                lbx.setAnyDependencyEventByKeyOnContainer<T, K>(kTemp, eventName, row_col + key, actionDelegate, shouldSubscribe);
            }

            return chain;
        }

        public static T SubscribeDependencyEventOnChild<K, T>(this T chain, string key, int row, int column, string eventName, Action<EventPattern<ValueChangedEventArgs>> actionDelegate)
            where T : FrameworkElement
            where K : FrameworkElement
        {
            var dispDict = chain.GetDisposablesDictionary<T>();
            var ChildLookupDict = chain.GetChildLookupDictionary();
            string row_col = "_" + row + "_" + column;
            string fullKey = key + row_col;

            if (!dispDict.ContainsKey(eventName + row_col + key))
            {
                K kTemp = (K)ChildLookupDict[fullKey];
                Predicate<K> shouldSubscribe = item => { return true; };
                chain.setAnyDependencyEventByKeyOnContainer<T, K>(kTemp, eventName, row_col + key, actionDelegate, shouldSubscribe);
            }

            return chain;
        }

        public static T SubscribeDependencyEventOnChild<K, T>(this T chain, K child, string key, int row, int column, string eventName, Action<EventPattern<ValueChangedEventArgs>> actionDelegate)
            where T : FrameworkElement
            where K : FrameworkElement
        {
            var dispDict = chain.GetDisposablesDictionary<T>();
            string row_col = "_" + row + "_" + column;
            string fullKey = key + row_col;

            if (!dispDict.ContainsKey(eventName + row_col + key))
            {
                Predicate<K> shouldSubscribe = item => { return true; };
                chain.setAnyDependencyEventByKeyOnContainer<T, K>(child, eventName, row_col + key, actionDelegate, shouldSubscribe);
            }

            return chain;
        }
        
        public static T SubscribeDependencyEventOnChild<K, T>(this T chain, K child, string key, int row, int column, string eventName, Action<EventPattern<ValueChangedEventArgs>> actionDelegate, Action<IConnectableObservable<EventPattern<ValueChangedEventArgs>>, Action<EventPattern<ValueChangedEventArgs>>> composeObservable)
            where T : FrameworkElement
            where K : FrameworkElement
        {
            var dispDict = chain.GetDisposablesDictionary<T>();
            string row_col = "_" + row + "_" + column;
            string fullKey = key + row_col;

            if (!dispDict.ContainsKey(eventName + row_col + key))
            {
                Predicate<K> shouldSubscribe = item => { return true; };
                chain.setAnyDependencyEventByKeyOnContainer<T, K>(child, eventName, row_col + key, actionDelegate, shouldSubscribe,composeObservable);
            }

            return chain;
        }

        /// <summary>
        /// Subscribe Event on Child.
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="key"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <param name="eventName"></param>
        /// <param name="deleg"></param>
        /// <returns></returns>
        public static T SubscribeEventOnChild<K, T, TEventArgs>(this T chain, string key, int row, int column, string eventName, Action<EventPattern<TEventArgs>> actionDelegate)
            where T : FrameworkElement
            where K : FrameworkElement
            where TEventArgs : EventArgs
        {
            var dispDict = chain.GetDisposablesDictionary<T>();
            var ChildLookupDict = chain.GetChildLookupDictionary();
            string row_col = "_" + row + "_" + column;
            string fullKey = key + row_col;

            if (!dispDict.ContainsKey(eventName + row_col + key))
            {
                K kTemp = (K)ChildLookupDict[fullKey];
                Predicate<K> shouldSubscribe = item => { return true; };
                chain.setAnyEventByKeyOnContainer<T, K, TEventArgs>(kTemp, eventName, row_col + key, actionDelegate, shouldSubscribe);
            }

            return chain;
        }

        /// <summary>
        /// Subscribe Event on Child.
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="key"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <param name="eventName"></param>
        /// <param name="deleg"></param>
        /// <returns></returns>
        public static T SubscribeEventOnChild<K, T, TEventArgs>(this T chain, K child, string key, int row, int column, string eventName, Action<EventPattern<TEventArgs>> actionDelegate)
            where T : FrameworkElement
            where K : FrameworkElement
            where TEventArgs : EventArgs
        {
            var dispDict = chain.GetDisposablesDictionary<T>();
            string row_col = "_" + row + "_" + column;
            string fullKey = key + row_col;

            if (!dispDict.ContainsKey(eventName + row_col + key))
            {
                Predicate<K> shouldSubscribe = item => { return true; };
                chain.setAnyEventByKeyOnContainer<T, K, TEventArgs>(child, eventName, row_col + key, actionDelegate, shouldSubscribe);
            }

            return chain;
        }

        /// <summary>
        /// Subscribe Event on Child filtering by a Predicate. Call within AddComposite method.
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="key"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <param name="eventName"></param>
        /// <param name="deleg"></param>
        /// <returns></returns>
        public static ContentControl SubscribeEventOnChild<K, T, TEventArgs>(this ContentControl chain, string key, int row, int column, string eventName, Action<EventPattern<TEventArgs>> actionDelegate, Predicate<K> shouldSubscribe)
            where T : FrameworkElement
            where K : FrameworkElement
            where TEventArgs : EventArgs

        {
            T lbx = chain.GetTFromChildContentControl<T>();
            var dispDict = lbx.GetDisposablesDictionary<T>();
            var ChildLookupDict = lbx.GetChildLookupDictionary();
            string row_col = "_" + row + "_" + column;
            string fullKey = key + row_col;

            if (!dispDict.ContainsKey(eventName + row_col + key))
            {
                K kTemp = (K)ChildLookupDict[fullKey];
                lbx.setAnyEventByKeyOnContainer<T, K, TEventArgs>(kTemp, eventName, row_col + key, actionDelegate, shouldSubscribe);
            }

            return chain;
        }

        /// <summary>
        /// Subscribe Event on Composite (Border) itself.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="b"></param>
        /// <param name="key"></param>
        /// <param name="eventName"></param>
        /// <param name="deleg"></param>
        /// <returns></returns>
        public static Border SubscribeEventOnBorder<T, TEventArgs>(this Border b, string key, string eventName, Action<EventPattern<TEventArgs>> actionDelegate)
where T : FrameworkElement
            where TEventArgs: EventArgs
        {
            T lbx = b.GetParentFromComposite<T>();
            var dispDict = lbx.GetDisposablesDictionary<T>();

            if (!dispDict.ContainsKey(eventName + "_Border_" + key))
            {
                Predicate<Border> shouldSubscribe = item => { return true; };
                lbx.setAnyEventByKeyOnContainer<T, Border, TEventArgs>(b, eventName, "_Border_" + key, actionDelegate, shouldSubscribe);
            }

            return b;
        }

        /// <summary>
        /// Subscribe Dependency Property Event on Composite (Border) itself.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="b"></param>
        /// <param name="key"></param>
        /// <param name="eventName"></param>
        /// <param name="deleg"></param>
        /// <returns></returns>
        public static Border SubscribeDependencyEventOnBorder<T>(this Border b, string key, string eventName, Action<EventPattern<ValueChangedEventArgs>> actionDelegate)
             where T : FrameworkElement
        {
            T lbx = b.GetParentFromComposite<T>();
            var dispDict = lbx.GetDisposablesDictionary<T>();

            if (!dispDict.ContainsKey(eventName + "_Border_" + key))
            {
                Predicate<Border> shouldSubscribe = item => { return true; };
                lbx.setAnyDependencyEventByKeyOnContainer<T, Border>(b, eventName, "_Border_" + key, actionDelegate, shouldSubscribe);
            }

            return b;
        }
        
        /// <summary>
        /// Conditionally subscribe Event on Composite (Border) itself.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="b"></param>
        /// <param name="key"></param>
        /// <param name="eventName"></param>
        /// <param name="deleg"></param>
        /// <param name="shouldSubscribe"></param>
        /// <returns></returns>
        public static Border SubscribeEventOnBorder<T, TEventArgs>(this Border b, string key, string eventName, Action<EventPattern<TEventArgs>> actionDelegate, Predicate<Border> shouldSubscribe)
            where T : FrameworkElement
            where TEventArgs : EventArgs
        {
            T lbx = b.GetParentFromComposite<T>();
            var dispDict = lbx.GetDisposablesDictionary<T>();

            if (!dispDict.ContainsKey(eventName + "_Border_" + key))
            {
                lbx.setAnyEventByKeyOnContainer<T, Border, TEventArgs>(b, eventName, "_Border_" + key, actionDelegate, shouldSubscribe);
            }

            return b;
        }

        /// <summary>
        /// Conditionally subscribe Dependency Property Event on Composite (Border) itself.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="b"></param>
        /// <param name="key"></param>
        /// <param name="eventName"></param>
        /// <param name="deleg"></param>
        /// <param name="shouldSubscribe"></param>
        /// <returns></returns>
        public static Border SubscribeDependencyEventOnBorder<T>(this Border b, string key, string eventName, Action<EventPattern<ValueChangedEventArgs>> actionDelegate, Predicate<Border> shouldSubscribe)
            where T : FrameworkElement
        {
            T lbx = b.GetParentFromComposite<T>();
            var dispDict = lbx.GetDisposablesDictionary<T>();

            if (!dispDict.ContainsKey(eventName + "_Border_" + key))
            {
                lbx.setAnyDependencyEventByKeyOnContainer<T, Border>(b, eventName, "_Border_" + key, actionDelegate, shouldSubscribe);
            }

            return b;
        }
        
        /// <summary>
        /// Subscribe any event by key on Composite's Container, e.g. if GridComposite this would be a Grid.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="eventName"></param>
        /// <param name="deleg"></param>
        /// <returns></returns>
        public static ContentControl SubscribeEventOnContainer<C, T, TEventArgs>(this ContentControl chain, string key, string eventName, Action<EventPattern<TEventArgs>> actionDelegate)
            where C : FrameworkElement
            where T : FrameworkElement            
            where TEventArgs : EventArgs
        {

            T source = chain.GetTFromChildContentControl<T>();
            IComposite icomp = SettingsManager.GetIComposite<T>(source);
            var dispDict = source.GetDisposablesDictionary<T>();
            C container = icomp.GetContainerFromChildContentControl<C>(chain);

            if (!dispDict.ContainsKey(eventName + "_Container_" + key))
            {
                Predicate<C> shouldSubscribe = item => { return true; };
                source.setAnyEventByKeyOnContainer<T, C, TEventArgs>((C)container, eventName, "_Container_" + key, actionDelegate, shouldSubscribe);
            }
            return chain;
        }

        /// <summary>
        /// Subscribe any Dependency Property event by key on Composite's Container, e.g. if GridComposite this would be a Grid.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="eventName"></param>
        /// <param name="deleg"></param>
        /// <returns></returns>
        public static ContentControl SubscribeDependencyEventOnContainer<C, T>(this ContentControl chain, string key, string eventName, Action<EventPattern<ValueChangedEventArgs>> actionDelegate)
            where C : FrameworkElement
            where T : FrameworkElement
        {

            T source = chain.GetTFromChildContentControl<T>();
            IComposite icomp = SettingsManager.GetIComposite<T>(source);
            var dispDict = source.GetDisposablesDictionary<T>();
            C container = icomp.GetContainerFromChildContentControl<C>(chain);

            if (!dispDict.ContainsKey(eventName + "_Container_" + key))
            {
                Predicate<C> shouldSubscribe = item => { return true; };
                source.setAnyDependencyEventByKeyOnContainer<T, C>((C)container, eventName, "_Container_" + key, actionDelegate, shouldSubscribe);
            }
            return chain;
        }

        /// <summary>
        /// Subscribe any Dependency Property event by key on Composite's Container, e.g. if GridComposite this would be a Grid.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="eventName"></param>
        /// <param name="deleg"></param>
        /// <returns></returns>
        public static ContentControl SubscribeDependencyEventOnContainer<C, T>(this ContentControl chain, string key, string eventName, Action<EventPattern<ValueChangedEventArgs>> actionDelegate, Predicate<C> shouldSubscribe)
            where C : FrameworkElement
            where T : FrameworkElement
        {
            T source = chain.GetTFromChildContentControl<T>();
            IComposite icomp = SettingsManager.GetIComposite<T>(source);
            var dispDict = source.GetDisposablesDictionary<T>();
            C container = icomp.GetContainerFromChildContentControl<C>(chain);

            if (!dispDict.ContainsKey(eventName + "_Container_" + key))
            {
                source.setAnyDependencyEventByKeyOnContainer<T, C>((C)container, eventName, "_Container_" + key, actionDelegate, shouldSubscribe);
            }
            return chain;
        }

        /// <summary>
        /// Subscribe any event by key on Composite's Container, e.g. if GridComposite this would be a Grid.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="eventName"></param>
        /// <param name="deleg"></param>
        /// <returns></returns>
        public static ContentControl SubscribeEventOnContainer<C, T, TEventArgs>(this ContentControl chain, string key, string eventName, Action<EventPattern<TEventArgs>> actionDelegate, Predicate<C> shouldSubscribe)
            where C : FrameworkElement
            where T : FrameworkElement
            where TEventArgs : EventArgs
        {

            T source = chain.GetTFromChildContentControl<T>();
            IComposite icomp = SettingsManager.GetIComposite<T>(source);
            var dispDict = source.GetDisposablesDictionary<T>();
            C container = icomp.GetContainerFromChildContentControl<C>(chain);

            if (!dispDict.ContainsKey(eventName + "_Container_" + key))
            {
                source.setAnyEventByKeyOnContainer<T, C, TEventArgs>((C)container, eventName, "_Container_" + key, actionDelegate, shouldSubscribe);
            }
            return chain;
        }

        /// <summary>
        /// Subscribe Event on Parent.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="eventName"></param>
        /// <param name="deleg"></param>
        /// <returns></returns>
        public static T SubscribeEventOnParent<T, TEventArgs>(this T chain, string eventName, Action<object, TEventArgs> actionDelegate)
            where T : FrameworkElement
            where TEventArgs : EventArgs
        {
            Action<EventPattern<TEventArgs>> indirectAction = ve =>
            {
                if (actionDelegate != null)
                {
                    actionDelegate(ve.Sender, ve.EventArgs);
                }
            };

            Predicate<T> shouldSubscribe = item => { return true; };

            var dispDict = chain.GetDisposablesDictionary<T>();
            if (!dispDict.ContainsKey(eventName))
            {
                chain.setAnyEventOnceOnParent<T, TEventArgs>(eventName, indirectAction, shouldSubscribe);
            }

            return chain;
        }

        /// <summary>
        /// Conditionally subscribe Event on Parent.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="eventName"></param>
        /// <param name="deleg"></param>
        /// <param name="shouldSubscribe"></param>
        /// <returns></returns>
        public static T SubscribeEventOnParent<T, TEventArgs>(this T chain, string eventName, Action<object, TEventArgs> actionDelegate, Predicate<T> shouldSubscribe)
            where T : FrameworkElement
            where TEventArgs : EventArgs
        {
            Action<EventPattern<TEventArgs>> indirectAction = ve =>
            {
                if (actionDelegate != null)
                {
                    actionDelegate(ve.Sender, ve.EventArgs);
                }
            };

            var dispDict = chain.GetDisposablesDictionary<T>();
            if (!dispDict.ContainsKey(eventName))
            {
                chain.setAnyEventOnceOnParent<T, TEventArgs>(eventName, indirectAction, shouldSubscribe);
            }

            return chain;
        }

        /// <summary>
        /// Subscribe Event on Parent. Signature for connectable is: (connectableObservable, actionDelegate).
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="eventName"></param>
        /// <param name="deleg"></param>
        /// <returns></returns>
        public static T SubscribeEventOnParent<T, TEventArgs>(this T chain, string eventName, Action<EventPattern<TEventArgs>> actionDelegate, Action<IConnectableObservable<EventPattern<TEventArgs>>, Action<EventPattern<TEventArgs>>> composeObservable)
            where T : FrameworkElement
            where TEventArgs : EventArgs
        {
            Predicate<T> shouldSubscribe = item => { return true; };

            var dispDict = chain.GetDisposablesDictionary<T>();
            if (!dispDict.ContainsKey(eventName))
            {
                chain.setAnyEventOnceOnParent<T, TEventArgs>(eventName, actionDelegate, shouldSubscribe, composeObservable);
            }

            return chain;
        }

        /// <summary>
        /// Subscribe Event on Parent.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="eventName"></param>
        /// <param name="deleg"></param>
        /// <returns></returns>
        public static T SubscribeEventOnParent<T, TEventArgs>(this T chain, string eventName, Action<EventPattern<TEventArgs>> actionDelegate)
            where T : FrameworkElement
            where TEventArgs : EventArgs
        {
            Predicate<T> shouldSubscribe = item => { return true; };

            var dispDict = chain.GetDisposablesDictionary<T>();
            if (!dispDict.ContainsKey(eventName))
            {
                chain.setAnyEventOnceOnParent<T, TEventArgs>(eventName, actionDelegate, shouldSubscribe);
            }

            return chain;
        }

        /// <summary>
        /// Conditionally subscribe Event on Parent.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="eventName"></param>
        /// <param name="deleg"></param>
        /// <param name="shouldSubscribe"></param>
        /// <returns></returns>
        public static T SubscribeEventOnParent<T, TEventArgs>(this T chain, string eventName, Action<EventPattern<TEventArgs>> actionDelegate, Predicate<T> shouldSubscribe)
            where T : FrameworkElement
            where TEventArgs : EventArgs
        {
            var dispDict = chain.GetDisposablesDictionary<T>();
            if (!dispDict.ContainsKey(eventName))
            {
                chain.setAnyEventOnceOnParent<T, TEventArgs>(eventName, actionDelegate, shouldSubscribe);
            }

            return chain;
        }

        /// <summary>
        /// Subscribe Event on Parent.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="eventName"></param>
        /// <param name="deleg"></param>
        /// <returns></returns>
        public static T SubscribeDependencyEventOnParent<T>(this T chain, string eventName, Action<EventPattern<ValueChangedEventArgs>> actionDelegate)
            where T : FrameworkElement
        {
            Predicate<T> shouldSubscribe = item => { return true; };

            var dispDict = chain.GetDisposablesDictionary<T>();
            if (!dispDict.ContainsKey(eventName))
            {
                chain.setAnyDependencyEventOnceOnParent<T>(eventName, actionDelegate, shouldSubscribe);
            }

            return chain;
        }

        /// <summary>
        /// Conditionally subscribe Event on Parent.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="eventName"></param>
        /// <param name="deleg"></param>
        /// <param name="shouldSubscribe"></param>
        /// <returns></returns>
        public static T SubscribeDependencyEventOnParent<T>(this T chain, string eventName, Action<EventPattern<ValueChangedEventArgs>> actionDelegate, Predicate<T> shouldSubscribe)
    where T : FrameworkElement
        {
            var dispDict = chain.GetDisposablesDictionary<T>();
            if (!dispDict.ContainsKey(eventName))
            {
                chain.setAnyDependencyEventOnceOnParent<T>(eventName, actionDelegate, shouldSubscribe);
            }

            return chain;
        }

        /// <summary>
        /// Sets selection changed on a Parent only. NOT meant to be used with child objects. Sets only one and only once.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="delegAction"></param>
        /// <returns></returns>
        public static T SubscribeSelectionChangedOnParent<T>(this T chain, Action<object, SelectionChangedEventArgs> delegAction)
              where T : FrameworkElement
        {
            Predicate<T> shouldSubscribe = item => { return true; };
            chain.StoreSetting<T>("SelectionChangedPredicate", shouldSubscribe);
            chain.StoreSetting<T>("SelectionChangedDelegate", new SelectionChangedEventHandler(delegAction));
            return chain;
        }

        /// <summary>
        /// Subscribe PreviewMouseLeftButtonDown on Composite (Border).
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="delegAction"></param>
        /// <returns></returns>
        public static T SubscribeMouseSingleClickOnBorder<T>(this T chain, Action<object, MouseButtonEventArgs> delegAction)
              where T : FrameworkElement
        {
            Predicate<Border> shouldSubscribe = item => { return true; };
            chain.StoreSetting<T>("SingleClickPredicate", shouldSubscribe);
            chain.StoreSetting<T>("SingleClickDelegate", new MouseButtonEventHandler(delegAction));
            return chain;
        }

        /// <summary>
        /// Subscribe PreviewMouseLeftButtonDown with ClickCount of 2 on Composite (Border).
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="delegAction"></param>
        /// <returns></returns>
        public static T SubscribeMouseDoubleClickOnBorder<T>(this T chain, Action<object, MouseButtonEventArgs> delegAction)
                      where T : FrameworkElement
        {
            Predicate<Border> shouldSubscribe = item => { return true; };
            chain.StoreSetting<T>("DoubleClickPredicate", shouldSubscribe);
            chain.StoreSetting<T>("DoubleClickDelegate", new MouseButtonEventHandler(delegAction));
            return chain;
        }

        /// <summary>
        /// Conditionally subscribe PreviewMouseLeftButtonDown on Composite (Border).
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="delegAction"></param>
        /// <param name="shouldSubscribe"></param>
        /// <returns></returns>
        public static T SubscribeMouseSingleClickOnBorder<T>(this T chain, Action<object, MouseButtonEventArgs> delegAction, Predicate<Border> shouldSubscribe)
       where T : FrameworkElement
        {
            chain.StoreSetting<T>("SingleClickPredicate", shouldSubscribe);
            chain.StoreSetting<T>("SingleClickDelegate", new MouseButtonEventHandler(delegAction));
            return chain;
        }

        /// <summary>
        /// Conditionally subscribe PreviewMouseLeftButtonDown with ClickCount of 2 on Composite (Border).
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="delegAction"></param>
        /// <param name="shouldSubscribe"></param>
        /// <returns></returns>
        public static T SubscribeMouseDoubleClickOnBorder<T>(this T chain, Action<object, MouseButtonEventArgs> delegAction, Predicate<Border> shouldSubscribe)
               where T : FrameworkElement
        {
            chain.StoreSetting<T>("DoubleClickPredicate", shouldSubscribe);
            chain.StoreSetting<T>("DoubleClickDelegate", new MouseButtonEventHandler(delegAction));
            return chain;
        }

        //DEPRECATED
        //        public static T SubscribeAnyEvent<T>(this T chain,  string eventName, object deleg, Predicate<T> shouldSubscribe)
        //where T : FrameworkElement
        //        {
        //            chain.StoreSetting<T>(eventName + "Predicate", shouldSubscribe);
        //            chain.StoreSetting<T>(eventName + "Delegate", deleg);
        //            return chain;
        //        }        

        /// <summary>
        /// Conditionally subscribe selection changed on a Parent. NOT meant to be used with child objects. Sets only one and only once.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="delegAction"></param>
        /// <param name="shouldSubscribe"></param>
        /// <returns></returns>
        public static T SubscribeSelectionChangedOnParent<T>(this T chain, Action<object, SelectionChangedEventArgs> delegAction, Predicate<T> shouldSubscribe)
       where T : FrameworkElement
        {
            chain.StoreSetting<T>("SelectionChangedPredicate", shouldSubscribe);
            chain.StoreSetting<T>("SelectionChangedDelegate", new SelectionChangedEventHandler(delegAction));
            return chain;
        }

        /// <summary>
        /// Conditionally subscribe selection changed on a Parent. NOT meant to be used with child objects. Sets only one and only once. This is for subscribing on-the-fly 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="txb"></param>
        /// <returns></returns>
        public static T SubscribeSelectionChangedOnParent<T>(this T chain)
     where T : FrameworkElement
        {
            Tuple<SelectionChangedEventHandler, Predicate<T>> mbeTuple = CommonExt.getSelectionChangedDelegateFromSettings(chain);

            chain.setSelectionChanged<T>(mbeTuple.Item1, mbeTuple.Item2);
            return chain;
        }

        /// <summary>
        /// Subscribe PreviewMouseLeftButtonDown on Composite (Border) [from but not on child element]. This is for subscribing on-the-fly.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="childElement"></param>
        /// <returns></returns>
        public static T SubscribeMouseSingleClickOnBorder<T>(this T chain, FrameworkElement childElement)
             where T : FrameworkElement
        {
            Tuple<MouseButtonEventHandler, Predicate<Border>> mbeTuple = CommonExt.getSingleClickDelegateFromSettings(chain);

            Border bdr = (Border)childElement.GetBorderFromChildElement<T>();

            bdr.setSingleClick(bdr.GetKey(), mbeTuple.Item1, mbeTuple.Item2);
            return chain;
        }

        /// <summary>
        /// Subscribe PreviewMouseLeftButtonDown with ClickCount of 2 on Composite (Border) [from but not on child element]. This is for subscribing on-the-fly.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="childElement"></param>
        /// <returns></returns>
        public static T SubscribeMouseDoubleClickOnBorder<T>(this T chain, FrameworkElement childElement)
             where T : FrameworkElement
        {
            Tuple<MouseButtonEventHandler, Predicate<Border>> mbeTuple = CommonExt.getDoubleClickDelegateFromSettings(chain);

            Border bdr = (Border)childElement.GetBorderFromChildElement<T>();

            bdr.setDoubleClick(bdr.GetKey(), mbeTuple.Item1, mbeTuple.Item2);
            return chain;
        }

        #endregion

        #region Get Delegates From Settings Dictionary

        private static Tuple<object, Predicate<T>> getAnyEventDelegateFromSettings<T>(T chain, string eventName)
    where T : FrameworkElement
        {
            object mbe = null;

            if (chain.ContainsSetting(eventName + "Delegate"))
            {
                mbe = chain.GetSetting<T, object>(eventName + "Delegate");
            }

            Predicate<T> pB = null;

            if (chain.ContainsSetting(eventName + "Predicate"))
            {
                pB = chain.GetSetting<T, Predicate<T>>(eventName + "Predicate");
            }

            var mbeTuple = new Tuple<object, Predicate<T>>(mbe, pB);
            return mbeTuple;
        }

        private static Tuple<SelectionChangedEventHandler, Predicate<T>> getSelectionChangedDelegateFromSettings<T>(T chain)
            where T : FrameworkElement
        {
            SelectionChangedEventHandler mbe = null;

            if (chain.ContainsSetting("SelectionChangedDelegate"))
            {
                mbe = chain.GetSetting<T, SelectionChangedEventHandler>("SelectionChangedDelegate");
            }

            Predicate<T> pB = null;

            if (chain.ContainsSetting("SelectionChangedPredicate"))
            {
                pB = chain.GetSetting<T, Predicate<T>>("SelectionChangedPredicate");
            }

            var mbeTuple = new Tuple<SelectionChangedEventHandler, Predicate<T>>(mbe, pB);
            return mbeTuple;
        }

        private static Tuple<MouseButtonEventHandler, Predicate<Border>> getSingleClickDelegateFromSettings<T>(T chain)
    where T : FrameworkElement
        {
            MouseButtonEventHandler mbe = null;

            if (chain.ContainsSetting("SingleClickDelegate"))
            {
                mbe = chain.GetSetting<T, MouseButtonEventHandler>("SingleClickDelegate");
            }

            Predicate<Border> pB = null;

            if (chain.ContainsSetting("SingleClickPredicate"))
            {
                pB = chain.GetSetting<T, Predicate<Border>>("SingleClickPredicate");
            }

            var mbeTuple = new Tuple<MouseButtonEventHandler, Predicate<Border>>(mbe, pB);
            return mbeTuple;
        }

        private static Tuple<MouseButtonEventHandler, Predicate<Border>> getDoubleClickDelegateFromSettings<T>(T chain)
            where T : FrameworkElement
        {
            MouseButtonEventHandler mbe = null;

            if (chain.ContainsSetting("DoubleClickDelegate"))
            {
                mbe = chain.GetSetting<T, MouseButtonEventHandler>("DoubleClickDelegate");
            }

            Predicate<Border> pB = null;

            if (chain.ContainsSetting("DoubleClickPredicate"))
            {
                pB = chain.GetSetting<T, Predicate<Border>>("DoubleClickPredicate");
            }

            var mbeTuple = new Tuple<MouseButtonEventHandler, Predicate<Border>>(mbe, pB);
            return mbeTuple;
        }

        #endregion

        #region Dispose

        /// <summary>
        /// Unsubscribe All Events in a Parent including ScrollViewer Events. This does NOT automatically recurse down thru all child Parents.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        public static void DisposeEvents<T>(this T chain)
            where T : FrameworkElement
        {
            var settings = chain.GetSettingsDictionary();
            //retrieveAndDispose(settings, "DragDeltaDisposable");
            //retrieveAndDispose(settings, "HorizDragDeltaDisposable");

            //retrieveAndDispose(settings, "VerticalScrollDownDisposable");
            //retrieveAndDispose(settings, "VerticalScrollDownClickDisposable");
            //retrieveAndDispose(settings, "VerticalPageDownDisposable");
            //retrieveAndDispose(settings, "RepeatButtonDownClickDisposable");

            //retrieveAndDispose(settings, "VerticalScrollUpDisposable");
            //retrieveAndDispose(settings, "VerticalScrollUpClickDisposable");
            //retrieveAndDispose(settings, "VerticalPageUpDisposable");
            //retrieveAndDispose(settings, "RepeatButtonUpClickDisposable");

            //retrieveAndDispose(settings, "HorizontalScrollRightDisposable");
            //retrieveAndDispose(settings, "HorizontalScrollRightClickDisposable");
            //retrieveAndDispose(settings, "HorizontalPageRightDisposable");
            //retrieveAndDispose(settings, "RepeatButtonRightClickDisposable");

            //retrieveAndDispose(settings, "HorizontalScrollLeftDisposable");
            //retrieveAndDispose(settings, "HorizontalScrollLeftClickDisposable");
            //retrieveAndDispose(settings, "HorizontalPageLeftDisposable");
            //retrieveAndDispose(settings, "RepeatButtonLeftClickDisposable");

            chain.UnsubscribeAll<T>();
        }

        public class ObservableDisposer : IDisposable
        {
            public object ObservableObject { get; set; }
            public IDisposable Disposable { get; set; }
            public object SubjectDelegate { get; set; }

            public ObservableDisposer(object iObservableObject, IDisposable disposable, object subjectDelegate)
            {
                ObservableObject = iObservableObject;
                Disposable = disposable;
                SubjectDelegate = subjectDelegate;
            }
            
            public void Dispose()
            {
                this.ObservableObject = null;
                this.SubjectDelegate = null;
                Disposable.Dispose();
            }
        }

        #region Old Code
        //public class EventDisposer : IDisposable
        //{
        //    public Action<Delegate> Wrapper { get; set; }
        //    public Delegate Deleg { get; set; }

        //    public EventDisposer(Action<Delegate> wrapper, Delegate deleg)
        //    {
        //        Wrapper = wrapper;
        //        Deleg = deleg;
        //    }

        //    public void Dispose()
        //    {
        //        Wrapper(Deleg);
        //    }
        //}
        #endregion

        private static void retrieveAndDispose(Dictionary<string, object> settings, string settingKey)
        {
            if (settings.Keys.Contains(settingKey))
            {
                ((IDisposable)settings[settingKey]).Dispose();
            }
        }

        #endregion

        #region Unsubscribe

        /// <summary>
        /// Unsubscribe All Events in a Parent excluding ScrollViewer Events (use DisposeEvents to include those.) This does NOT automatically recurse down thru all child Parents.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        private static void UnsubscribeAll<T>(this T chain) where T : FrameworkElement
        {
            Dictionary<string, IDisposable> eventsDict = CommonExt.GetDisposablesDictionary(chain);

            List<string> keysToRemove = new List<string>();
            foreach (string x in eventsDict.Keys)
            {
                keysToRemove.Add(x);
            }

            if (keysToRemove != null && keysToRemove.Count > 0)
            {
                foreach (string fullKey in keysToRemove)
                {
                    IDisposable idisp = eventsDict[fullKey];
                    //REMOVE_FROM_DICTIONARY BOOKMARK - 4. DISPOSABLES DICTIONARY 
                    eventsDict.Remove(fullKey);
                    idisp.Dispose();
                }
            }
        }

        /// <summary>
        /// Unsubscribe by key and event name an event from Composite (Border) itself. NOT for unsubscribing Child events within a Composite.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="eventName"></param>
        /// <param name="key"></param>
        public static void UnsubscribeBorderEventByKey<T>(this T chain, string eventName, string key)
where T : FrameworkElement
        {
            commonUnsubscribeClickAll<T>(chain, eventName + "_Border_" + key);
        }

        /// <summary>
        /// Unsubscribe by key and event name an event from Composite's Container--e.g. if GridComposite this would be a Grid.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="eventName"></param>
        /// <param name="key"></param>
        public static void UnsubscribeContainerEventByKey<T>(this T chain, string eventName, string key)
where T : FrameworkElement
        {
            commonUnsubscribeClickAll<T>(chain, eventName + "_Container_" + key);
        }

        /// <summary>
        /// Unsubscribe PreviewMouseDown Event (with ClickCount of 1) by key from Composite's Container--e.g. if GridComposite this would be a Grid.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="eventName"></param>
        /// <param name="key"></param>
        public static void UnsubscribeMouseSingleClickOnContainerByKey<T>(this T chain, string key)
where T : FrameworkElement
        {
            commonUnsubscribeClickAll<T>(chain, "PreviewMouseDown" + "_Container_" + key);
        }

        /// <summary>
        /// Unsubscribe PreviewMouseDown Event (with ClickCount of 2) by key from Composite's Container--e.g. if GridComposite this would be a Grid.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="eventName"></param>
        /// <param name="key"></param>
        public static void UnsubscribeMouseDoubleClickOnContainerByKey<T>(this T chain, string key)
where T : FrameworkElement
        {
            commonUnsubscribeClickAll<T>(chain, "PreviewMouseDown" + "_Container_" + key);
        }

        /// <summary>
        /// Unsubscribe an Event on a Parent.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="eventName"></param>
        public static void UnsubscribeParentEvent<T>(this T chain, string eventName)
    where T : FrameworkElement
        {
            commonUnsubscribeClickAll<T>(chain, eventName);
        }

        /// <summary>
        /// Unsubscribe SelectionChanged from a Parent.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        public static void UnsubscribeSelectionChangedOnParent<T>(this T chain)
            where T : FrameworkElement
        {
            commonUnsubscribeClickAll<T>(chain, "SelectionChanged");
        }

        /// <summary>
        /// Unsubscribe by key ALL events from a Composite. This may unsubscribe BOTH Child Events AND events on Border itself.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="key"></param>
        public static void UnsubscribeBothChildAndBorderEventsByKey<T>(this T chain, string key)
where T : FrameworkElement
        {
            Dictionary<string, IDisposable> eventsDict = CommonExt.GetDisposablesDictionary(chain);
            List<string> keysToRemove = getMatchingChildKeysFromDisposablesDictionaryViaStrContains<T>(chain, key);

            foreach (var k in keysToRemove)
            {
                IDisposable idisp = eventsDict[k];
                //REMOVE_FROM_DICTIONARY BOOKMARK - 4. DISPOSABLES DICTIONARY 
                eventsDict.Remove(k);
                idisp.Dispose();
            }
        }

        /// <summary>
        /// Unsubscribe by key ALL Child events from a Composite. This will NOT unsubscribe events on Composite (Border) itself.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="key"></param>
        public static void UnsubscribeChildEventsByKey<T>(this T chain, string key)
where T : FrameworkElement
        {
            Dictionary<string, IDisposable> eventsDict = CommonExt.GetDisposablesDictionary(chain);
            List<string> keysToRemove = getMatchingChildKeysFromDisposablesDictionaryViaStrContains<T>(chain, key);
            List<string> keysToExclude = getMatchingChildKeysFromDisposablesDictionaryViaStrContains<T>(chain, "_Border_" + key);

            List<string> keysCleaned = new List<String>();

            foreach (var r in keysToRemove)
            {
                if (!keysToExclude.Contains(r))
                {
                    keysCleaned.Add(r);
                }
            }

            foreach (var k in keysCleaned)
            {
                IDisposable idisp = eventsDict[k];
                //REMOVE_FROM_DICTIONARY BOOKMARK - 4. DISPOSABLES DICTIONARY 
                eventsDict.Remove(k);
                idisp.Dispose();
            }
        }

        /// <summary>
        /// Unsubscribe by key ALL events from Composite (Border) itself. NOT for unsubscribing Child events within a Composite.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="key"></param>
        public static void UnsubscribeBorderEventsByKey<T>(this T chain, string key)
 where T : FrameworkElement
        {
            Dictionary<string, IDisposable> eventsDict = CommonExt.GetDisposablesDictionary(chain);
            List<string> keysToRemove = getMatchingChildKeysFromDisposablesDictionaryViaStrContains<T>(chain, "_Border_" + key);

            foreach (var k in keysToRemove)
            {
                IDisposable idisp = eventsDict[k];
                //REMOVE_FROM_DICTIONARY BOOKMARK - 4. DISPOSABLES DICTIONARY 
                eventsDict.Remove(k);
                idisp.Dispose();
            }
        }

        /// <summary>
        /// Unsubscribe by key ALL events from Composite's Container--e.g. if GridComposite this would be a Grid.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="key"></param>
        public static void UnsubscribeContainerEventsByKey<T>(this T chain, string key)
where T : FrameworkElement
        {
            Dictionary<string, IDisposable> eventsDict = CommonExt.GetDisposablesDictionary(chain);
            List<string> keysToRemove = getMatchingChildKeysFromDisposablesDictionaryViaStrContains<T>(chain, "_Container_" + key);

            foreach (var k in keysToRemove)
            {
                IDisposable idisp = eventsDict[k];
                //REMOVE_FROM_DICTIONARY BOOKMARK - 4. DISPOSABLES DICTIONARY 
                eventsDict.Remove(k);
                idisp.Dispose();
            }
        }

        /// <summary>
        /// Unsubscribe ALL events from ALL Composites (Borders), only from the Border itself. NOT for unsubscribing Child events within a Composite.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        public static void UnsubscribeBorderEvents<T>(this T chain)
where T : FrameworkElement
        {
            List<String> orderedKeyList = chain.GetOrderedKeyList();
            Dictionary<string, IDisposable> eventsDict = CommonExt.GetDisposablesDictionary(chain);
            List<string> keysToRemove = null;

            foreach (string key in orderedKeyList)
            {
                if (keysToRemove != null)
                {
                    keysToRemove.Clear();
                }

                keysToRemove = getMatchingChildKeysFromDisposablesDictionaryViaStrContains<T>(chain, "_Border_" + key);

                foreach (var k in keysToRemove)
                {
                    IDisposable idisp = eventsDict[k];
                    //REMOVE_FROM_DICTIONARY BOOKMARK - 4. DISPOSABLES DICTIONARY 
                    eventsDict.Remove(k);
                    idisp.Dispose();
                }
            }
        }

        /// <summary>
        /// Unsubscribe ALL events from ALL Composite Containers--e.g. if GridComposites the containers would be Grids.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        public static void UnsubscribeContainerEventsAll<T>(this T chain)
where T : FrameworkElement
        {
            List<String> orderedKeyList = chain.GetOrderedKeyList();
            Dictionary<string, IDisposable> eventsDict = CommonExt.GetDisposablesDictionary(chain);
            List<string> keysToRemove = null;

            foreach (string key in orderedKeyList)
            {
                if (keysToRemove != null)
                {
                    keysToRemove.Clear();
                }

                keysToRemove = getMatchingChildKeysFromDisposablesDictionaryViaStrContains<T>(chain, "_Container_" + key);

                foreach (var k in keysToRemove)
                {
                    IDisposable idisp = eventsDict[k];
                    //REMOVE_FROM_DICTIONARY BOOKMARK - 4. DISPOSABLES DICTIONARY 
                    eventsDict.Remove(k);
                    idisp.Dispose();
                }
            }
        }

        /// <summary>
        /// Unsubscribe PreviewMouseLeftButtonDown from ALL Composites (Borders). This method is called on the Parent.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        public static void UnsubscribeMouseSingleClickOnBorderAll<T>(this T chain, bool clearSetting)
    where T : FrameworkElement
        {
            List<String> orderedKeyList = chain.GetOrderedKeyList();
            Dictionary<string, IDisposable> eventsDict = CommonExt.GetDisposablesDictionary(chain);
            List<string> keysToRemove = null;

            foreach (string key in orderedKeyList)
            {
                if (keysToRemove != null)
                {
                    keysToRemove.Clear();
                }

                keysToRemove = getMatchingChildKeysFromDisposablesDictionary<T>(chain, "SingleClick" + key);

                foreach (var k in keysToRemove)
                {
                    IDisposable idisp = eventsDict[k];
                    //REMOVE_FROM_DICTIONARY BOOKMARK - 4. DISPOSABLES DICTIONARY 
                    eventsDict.Remove(k);
                    idisp.Dispose();
                }
            }

            if (clearSetting)
            {
                chain.ClearEventSettings<T>(EventsType.SingleClick);
            }
        }

        public enum EventsType
        {
            SingleClick,
            DoubleClick,
            SelectionChanged
        }

        public static void ClearEventSettings<T>(this T chain, EventsType evType) where T : FrameworkElement
        {
            if (evType == EventsType.SingleClick)
            {
                chain.RemoveSetting<T>("SingleClickPredicate");
                chain.RemoveSetting<T>("SingleClickDelegate");
            }

            if (evType == EventsType.DoubleClick)
            {
                chain.RemoveSetting<T>("DoubleClickPredicate");
                chain.RemoveSetting<T>("DoubleClickDelegate");
            }

            if (evType == EventsType.SelectionChanged)
            {
                chain.RemoveSetting<T>("SelectionChangedPredicate");
                chain.RemoveSetting<T>("SelectionChangedDelegate");
            }
        }

        /// <summary>
        /// Unsubscribe PreviewMouseLeftButtonDown with ClickCount of 2 from ALL Composites (Borders). This method is called on the Parent.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        public static void UnsubscribeMouseDoubleClickOnBorderAll<T>(this T chain, bool clearSetting)
            where T : FrameworkElement
        {
            List<String> orderedKeyList = chain.GetOrderedKeyList();
            Dictionary<string, IDisposable> eventsDict = CommonExt.GetDisposablesDictionary(chain);
            List<string> keysToRemove = null;

            foreach (string key in orderedKeyList)
            {
                if (keysToRemove != null)
                {
                    keysToRemove.Clear();
                }

                keysToRemove = getMatchingChildKeysFromDisposablesDictionary<T>(chain, "DoubleClick" + key);

                foreach (var k in keysToRemove)
                {
                    IDisposable idisp = eventsDict[k];
                    //REMOVE_FROM_DICTIONARY BOOKMARK - 4. DISPOSABLES DICTIONARY 
                    eventsDict.Remove(k);
                    idisp.Dispose();
                }
            }

            if (clearSetting)
            {
                chain.ClearEventSettings<T>(EventsType.DoubleClick);
            }
        }

        //    public static T UnsubscribeAnyEventByKey<T>(this T chain, string key, string eventName)
        //where T : FrameworkElement
        //    {
        //        return commonUnsubscribeClickByKey<T>(chain, key, eventName);
        //    }

        /// <summary>
        /// Unsubscribe by key PreviewMouseLeftButtonDown from Composite (Border) itself. This method is called on the Parent.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static T UnsubscribeMouseSingleClickOnBorderByKey<T>(this T chain, string key)
            where T : FrameworkElement
        {
            return commonUnsubscribeClickByKey<T>(chain, key, "SingleClick");
        }

        /// <summary>
        /// Unsubscribe by key PreviewMouseLeftButtonDown with ClickCount of 2 from Composite (Border) itself. This method is called on the Parent.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static T UnsubscribeMouseDoubleClickOnBorderByKey<T>(this T chain, string key)
            where T : FrameworkElement
        {
            return commonUnsubscribeClickByKey<T>(chain, key, "DoubleClick");
        }

        /// <summary>
        /// Unsubscribe PreviewMouseDown Event (with ClickCount of 2) by Event Name from a Child at X-Y (row-column) within a Composite (Border) found by key on a Parent T
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="key"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <returns></returns>
        public static T UnsubscribeMouseDoubleClickOnChild<T>(this T chain, string key, int row, int column)
    where T : FrameworkElement
        {
            return chain.UnsubscribeChildEvent<T>(key, row, column, "PreviewMouseDown");
        }

        /// <summary>
        /// Unsubscribe PreviewMouseDown Event (with ClickCount of 1) by Event Name from a Child at X-Y (row-column) within a Composite (Border) found by key on a Parent T
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="key"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <returns></returns>
        public static T UnsubscribeMouseSingleClickOnChild<T>(this T chain, string key, int row, int column)
    where T : FrameworkElement
        {
            return chain.UnsubscribeChildEvent<T>(key, row, column, "PreviewMouseDown");
        }

        /// <summary>
        /// Unsubscribe PreviewMouseDown Event (with ClickCount of 1) by Event Name from a Parent T
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        public static void UnsubscribeMouseSingleClickOnParent<T>(this T chain)
    where T : FrameworkElement
        {
            chain.UnsubscribeParentEvent<T>("PreviewMouseDown");
        }

        /// <summary>
        /// Unsubscribe PreviewMouseDown Event (with ClickCount of 2) by Event Name from a Parent T
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        public static void UnsubscribeMouseDoubleClickOnParent<T>(this T chain)
    where T : FrameworkElement
        {
            chain.UnsubscribeParentEvent<T>("PreviewMouseDown");
        }

        /// <summary>
        /// Unsubscribe an Event by Event Name from a Child at X-Y (row-column) within a Composite (Border) found by key on a Parent T
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="key"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <param name="eventName"></param>
        /// <returns></returns>
        public static T UnsubscribeChildEvent<T>(this T chain, string key, int row, int column, string eventName)
    where T : FrameworkElement
        {
            string row_col = "_" + row + "_" + column;
            string suffixKey = row_col + key;

            return commonUnsubscribeClickByKey<T>(chain, suffixKey, eventName);
        }

        #endregion

        #region Private Set Events

        private static void commonUnsubscribeClickAll<T>(T chain, string eventKey) where T : FrameworkElement
        {
            Dictionary<string, IDisposable> eventsDict = CommonExt.GetDisposablesDictionary(chain);

            List<string> keysToRemove = getMatchingChildKeysFromDisposablesDictionary(chain, eventKey);

            foreach (var k in keysToRemove)
            {
                IDisposable idisp = eventsDict[k];
                //REMOVE_FROM_DICTIONARY BOOKMARK - 4. DISPOSABLES DICTIONARY 
                eventsDict.Remove(k);
                idisp.Dispose();
            }
        }

        private static T commonUnsubscribeClickByKey<T>(T chain, string key, string eventKey) where T : FrameworkElement
        {
            string fullKey = eventKey + key;
            Dictionary<string, IDisposable> eventsDict = CommonExt.GetDisposablesDictionary(chain);

            if (eventsDict.ContainsKey(fullKey))
            {
                IDisposable idisp = eventsDict[fullKey];
                //REMOVE_FROM_DICTIONARY BOOKMARK - 4. DISPOSABLES DICTIONARY 
                eventsDict.Remove(fullKey);
                idisp.Dispose();
            }

            return chain;
        }

        private static List<string> getMatchingChildKeysFromDisposablesDictionaryViaStrContains<T>(T chain, string key)
    where T : FrameworkElement
        {
            var matchingKeys = new List<string>();
            Dictionary<string, IDisposable> keyDictionary = CommonExt.GetDisposablesDictionary(chain);

            foreach (var keyItem in keyDictionary)
            {
                if (keyItem.Key.Contains(key))
                {
                    matchingKeys.Add(keyItem.Key);
                }
            }

            return matchingKeys;
        }

        private static List<string> getMatchingChildKeysFromDisposablesDictionary<T>(T chain, string key)
     where T : FrameworkElement
        {
            var matchingKeys = new List<string>();
            Dictionary<string, IDisposable> keyDictionary = CommonExt.GetDisposablesDictionary(chain);

            foreach (var keyItem in keyDictionary)
            {
                if (keyItem.Key == key)
                {
                    matchingKeys.Add(keyItem.Key);
                }
            }

            return matchingKeys;
        }

        #region Old Code
        ///// <summary>
        ///// Sets any event on a child. NOT meant to be used with parent objects. May set multiple children since it is keyed.
        ///// </summary>
        ///// <typeparam name="T"></typeparam>
        ///// <param name="chain"></param>
        ///// <param name="deleg"></param>
        ///// <param name="peb"></param>
        ///// <returns></returns>
        //private static FrameworkElement setAnyEventOnComposite(this FrameworkElement chain, string key, string eventName, object deleg, Predicate<Border> peb)
        //{      
        //    if (deleg != null && peb != null && peb((Border)chain))
        //    {
        //        EventInfo evi = chain.GetType().GetEvent(eventName);
        //        evi.AddEventHandler(chain, deleg as Delegate);
        //        Action<object, Delegate> unsub = (o, d) => { evi.RemoveEventHandler(o, d); };
        //        Action<Delegate> u2 = (d) => { unsub(chain, d); };

        //        EventDisposer evd = new EventDisposer(u2, deleg as Delegate);

        //        //Store IDisposable in Dictionary
        //        Dictionary<string, IDisposable> eventsList = ((Border)chain).GetDisposablesDictionaryFromBorder();
        //        AddToDisposablesDictionary(eventName + key, evd, eventsList);
        //    }

        //    return chain.Cast<FrameworkElement>();
        //}
        #endregion

        /// <summary>
        /// Sets any event on a parent container only. NOT meant to be used with child objects. Sets only one and only once.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="deleg"></param>
        /// <param name="peb"></param>
        /// <returns></returns>
        private static FrameworkElement setAnyEventByKeyOnContainer<T, K, TEventArgs>(this T source, K chain, string eventName, string key, Action<EventPattern<TEventArgs>> actionDelegate, Predicate<K> peb)
            where T : FrameworkElement
            where K : FrameworkElement
            where TEventArgs : EventArgs
        {
              if (actionDelegate != null && peb != null && peb((K)chain))
              {
                  var mouseSingleClick = Observable.FromEventPattern<TEventArgs>(((K)chain), eventName);

                  Subject<EventPattern<TEventArgs>> sjbct = new Subject<EventPattern<TEventArgs>>();
                  IObservable<EventPattern<TEventArgs>> iobs = sjbct.AsObservable();

                  var s = mouseSingleClick.Merge<EventPattern<TEventArgs>>(iobs).Subscribe(actionDelegate);

                  
                  //Store IDisposable in Dictionary
                  Dictionary<string, IDisposable> eventsList = source.GetDisposablesDictionary();
                  AddToDisposablesDictionary(eventName + key, new ObservableDisposer(mouseSingleClick, s, sjbct), eventsList);
              }

            return chain.Cast<FrameworkElement>();
        }

        /// <summary>
        /// Sets any event on a parent container only. NOT meant to be used with child objects. Sets only one and only once.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="deleg"></param>
        /// <param name="peb"></param>
        /// <returns></returns>
        private static FrameworkElement setAnyEventByKeyOnContainer<T, K, TEventArgs>(this T source, K chain, string eventName, string key, Action<EventPattern<TEventArgs>> actionDelegate, Predicate<K> peb, Action<IConnectableObservable<EventPattern<TEventArgs>>, Action<EventPattern<TEventArgs>>> composeObservable)
            where T : FrameworkElement
            where K : FrameworkElement
            where TEventArgs : EventArgs
        {
            if (actionDelegate != null && peb != null && peb((K)chain))
            {
                var mouseSingleClick = Observable.FromEventPattern<TEventArgs>(((K)chain), eventName);
                Subject<EventPattern<TEventArgs>> sjbct = new Subject<EventPattern<TEventArgs>>();
                IObservable<EventPattern<TEventArgs>> iobs = sjbct.AsObservable();

               // composeObservable(eventPattern mouseSingleClick.Subscribe(actionDelegate) );
                var c = mouseSingleClick.Merge<EventPattern<TEventArgs>>(iobs).Publish();
                composeObservable(c, actionDelegate);
                var s = c.Connect();

                //Store IDisposable in Dictionary
                Dictionary<string, IDisposable> eventsList = source.GetDisposablesDictionary();
                AddToDisposablesDictionary(eventName + key, new ObservableDisposer(mouseSingleClick, s, sjbct), eventsList);
            }

            return chain.Cast<FrameworkElement>();
        }

        #region Old Code
        //if (deleg != null && peb != null && peb((K)chain))
        //{
        //    EventInfo evi = chain.GetType().GetEvent(eventName);
        //    evi.AddEventHandler(chain, deleg as Delegate);
        //    Action<object, Delegate> unsub = (o, d) => { evi.RemoveEventHandler(o, d); };
        //    Action<Delegate> u2 = (d) => { unsub(chain, d); };

        //    EventDisposer evd = new EventDisposer(u2, deleg as Delegate);

        //    //Store IDisposable in Dictionary
        //    Dictionary<string, IDisposable> eventsList = source.GetDisposablesDictionary();
        //    AddToDisposablesDictionary(eventName + key, evd, eventsList);
        //}
        #endregion
        
        private static FrameworkElement setAnyDependencyEventByKeyOnContainer<T, K>(this T source, K chain, string eventName, string key, Action<EventPattern<ValueChangedEventArgs>> actionDelegate, Predicate<K> peb, Action<IConnectableObservable<EventPattern<ValueChangedEventArgs>>, Action<EventPattern<ValueChangedEventArgs>>> composeObservable)
            where T : FrameworkElement
            where K : FrameworkElement
        {      
            if (actionDelegate != null && peb != null && peb((K)chain))
            {                       
                var listener = new DependencyEventListener(chain);
                IObservable<EventPattern<ValueChangedEventArgs>> eventAsObservable = Observable.FromEventPattern<ValueChangedEventArgs>(
                   ev =>
                   {
                       K chainStore = (K)chain;
                       string eventNameStore = eventName;
                       EventInfo eviStore = chainStore.GetType().GetEvent(eventNameStore);
                       DependencyEventListener listenerStore = listener;
                       listenerStore.ValueChanged += ev;
                       listenerStore.SubscribeEvent(eviStore);
                   },
                   ev =>
                   {
                       K chainStore = (K)chain;
                       string eventNameStore = eventName;
                       EventInfo eviStore = chainStore.GetType().GetEvent(eventNameStore);
                       DependencyEventListener listenerStore = listener;
                       listenerStore.ValueChanged -= ev;
                       listenerStore.UnsubscribeEvent(eviStore);
                   }
                   );

                Subject<EventPattern<ValueChangedEventArgs>> sjbct = new Subject<EventPattern<ValueChangedEventArgs>>();
                IObservable<EventPattern<ValueChangedEventArgs>> iobs = sjbct.AsObservable();

                var c = eventAsObservable.Merge<EventPattern<ValueChangedEventArgs>>(iobs).Publish();
                composeObservable(c, actionDelegate);
                var s = c.Connect();
                
                //Store IDisposable in Dictionary
                Dictionary<string, IDisposable> eventsList = source.GetDisposablesDictionary();
                AddToDisposablesDictionary(eventName + key, new ObservableDisposer(eventAsObservable, s, sjbct), eventsList);
            }

            return chain.Cast<FrameworkElement>();
        }

        private static FrameworkElement setAnyDependencyEventByKeyOnContainer<T, K>(this T source, K chain, string eventName, string key, Action<EventPattern<ValueChangedEventArgs>> actionDelegate, Predicate<K> peb)
            where T : FrameworkElement
            where K : FrameworkElement
        {      
            if (actionDelegate != null && peb != null && peb((K)chain))
            {                       
                var listener = new DependencyEventListener(chain);
                IObservable<EventPattern<ValueChangedEventArgs>> eventAsObservable = Observable.FromEventPattern<ValueChangedEventArgs>(
                   ev =>
                   {
                       K chainStore = (K)chain;
                       string eventNameStore = eventName;
                       EventInfo eviStore = chainStore.GetType().GetEvent(eventNameStore);
                       DependencyEventListener listenerStore = listener;
                       listenerStore.ValueChanged += ev;
                       listenerStore.SubscribeEvent(eviStore);
                   },
                   ev =>
                   {
                       K chainStore = (K)chain;
                       string eventNameStore = eventName;
                       EventInfo eviStore = chainStore.GetType().GetEvent(eventNameStore);
                       DependencyEventListener listenerStore = listener;
                       listenerStore.ValueChanged -= ev;
                       listenerStore.UnsubscribeEvent(eviStore);
                   }
                   );

                Subject<EventPattern<ValueChangedEventArgs>> sjbct = new Subject<EventPattern<ValueChangedEventArgs>>();
                IObservable<EventPattern<ValueChangedEventArgs>> iobs = sjbct.AsObservable();

                var s = eventAsObservable.Merge<EventPattern<ValueChangedEventArgs>>(iobs).Subscribe(actionDelegate);
                
                //Store IDisposable in Dictionary
                Dictionary<string, IDisposable> eventsList = source.GetDisposablesDictionary();
                AddToDisposablesDictionary(eventName + key, new ObservableDisposer(eventAsObservable, s, sjbct), eventsList);
            }

            return chain.Cast<FrameworkElement>();
        }
                
        /// <summary>
        /// Sets any event on a parent container only. NOT meant to be used with child objects. Sets only one and only once.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="deleg"></param>
        /// <param name="peb"></param>
        /// <returns></returns>
        private static FrameworkElement setAnyEventOnceOnParent<T, TEventArgs>(this T chain, string eventName, Action<EventPattern<TEventArgs>> actionDelegate, Predicate<T> peb)
            where T : FrameworkElement
            where TEventArgs : EventArgs
        {
            if (actionDelegate != null && peb != null && peb((T)chain))
            {
                var mouseSingleClick = Observable.FromEventPattern<TEventArgs>(((T)chain), eventName);

                Subject<EventPattern<TEventArgs>> sjbct = new Subject<EventPattern<TEventArgs>>();
                IObservable<EventPattern<TEventArgs>> iobs = sjbct.AsObservable();

                var s = mouseSingleClick.Merge<EventPattern<TEventArgs>>(iobs).Subscribe(actionDelegate);

                //Store IDisposable in Dictionary
                Dictionary<string, IDisposable> eventsList = chain.GetDisposablesDictionary();
                AddToDisposablesDictionary(eventName, new ObservableDisposer(mouseSingleClick, s, sjbct), eventsList);
            }

            return chain.Cast<FrameworkElement>();
        }

        /// <summary>
        /// Sets any event on a parent container only. NOT meant to be used with child objects. Sets only one and only once.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="deleg"></param>
        /// <param name="peb"></param>
        /// <returns></returns>
        private static FrameworkElement setAnyEventOnceOnParent<T, TEventArgs>(this T chain, string eventName, Action<EventPattern<TEventArgs>> actionDelegate, Predicate<T> peb, Action<IConnectableObservable<EventPattern<TEventArgs>>, Action<EventPattern<TEventArgs>>>  composeObservable)
            where T : FrameworkElement
            where TEventArgs : EventArgs
        {
            if (actionDelegate != null && peb != null && peb((T)chain))
            {
                var mouseSingleClick = Observable.FromEventPattern<TEventArgs>(((T)chain), eventName);

                Subject<EventPattern<TEventArgs>> sjbct = new Subject<EventPattern<TEventArgs>>();
                IObservable<EventPattern<TEventArgs>> iobs = sjbct.AsObservable();

                var c = mouseSingleClick.Merge<EventPattern<TEventArgs>>(iobs).Publish();
                composeObservable(c, actionDelegate);
                var s = c.Connect();
        
                //Store IDisposable in Dictionary
                Dictionary<string, IDisposable> eventsList = chain.GetDisposablesDictionary();
                AddToDisposablesDictionary(eventName, new ObservableDisposer(mouseSingleClick, s, sjbct), eventsList);
            }           

            return chain.Cast<FrameworkElement>();
        }
          
        /// <summary>
        /// Sets any event on a parent container only. NOT meant to be used with child objects. Sets only one and only once.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="deleg"></param>
        /// <param name="peb"></param>
        /// <returns></returns>
        private static FrameworkElement setAnyDependencyEventOnceOnParent<T>(this T chain, string eventName, Action<EventPattern<ValueChangedEventArgs>> actionDelegate, Predicate<T> peb)
    where T : FrameworkElement
        {
            if (actionDelegate != null && peb != null && peb((T)chain))
            {
                var listener = new DependencyEventListener(chain);
                IObservable<EventPattern<ValueChangedEventArgs>> eventAsObservable = Observable.FromEventPattern<ValueChangedEventArgs>(
                   ev =>
                   {
                       T chainStore = (T)chain;
                       string eventNameStore = eventName;
                       EventInfo eviStore = chainStore.GetType().GetEvent(eventNameStore);
                       DependencyEventListener listenerStore = listener;
                       listenerStore.ValueChanged += ev;
                       listenerStore.SubscribeEvent(eviStore);
                   },
                   ev =>
                   {
                       T chainStore = (T)chain;
                       string eventNameStore = eventName;
                       EventInfo eviStore = chainStore.GetType().GetEvent(eventNameStore);
                       DependencyEventListener listenerStore = listener;
                       listenerStore.ValueChanged -= ev;
                       listenerStore.UnsubscribeEvent(eviStore);
                   }
                   );

                Subject<EventPattern<ValueChangedEventArgs>> sjbct = new Subject<EventPattern<ValueChangedEventArgs>>();
                IObservable<EventPattern<ValueChangedEventArgs>> iobs = sjbct.AsObservable();

                var s = eventAsObservable.Merge<EventPattern<ValueChangedEventArgs>>(iobs).Subscribe(actionDelegate);

                //Store IDisposable in Dictionary
                Dictionary<string, IDisposable> eventsList = chain.GetDisposablesDictionary();
                AddToDisposablesDictionary(eventName, new ObservableDisposer(eventAsObservable, s, sjbct), eventsList);
            }

            return chain.Cast<FrameworkElement>();
        }

        /// <summary>
        /// Sets selection changed on a parent container only. NOT meant to be used with child objects. Sets only one and only once.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="deleg"></param>
        /// <param name="peb"></param>
        /// <returns></returns>
        private static FrameworkElement setSelectionChanged<T>(this T chain, SelectionChangedEventHandler deleg, Predicate<T> peb)
            where T : FrameworkElement
        {
            if (deleg != null && peb != null && peb((T)chain))
            {
                var mySelectionChanged = Observable.FromEventPattern<SelectionChangedEventArgs>(chain, "SelectionChanged");

                Action<EventPattern<SelectionChangedEventArgs>> actionDelegate = pattern =>
                {
                    if (deleg != null)
                    {
                        deleg(chain.Cast<T>(), pattern.EventArgs);
                    }
                };

                Subject<EventPattern<SelectionChangedEventArgs>> sjbct = new Subject<EventPattern<SelectionChangedEventArgs>>();
                IObservable<EventPattern<SelectionChangedEventArgs>> iobs = sjbct.AsObservable();
                var s = mySelectionChanged.Merge<EventPattern<SelectionChangedEventArgs>>(iobs).Subscribe(actionDelegate);

                //Store IDisposable in Dictionary
                Dictionary<string, IDisposable> eventsList = chain.GetDisposablesDictionary();
                AddToDisposablesDictionary("SelectionChanged", new ObservableDisposer(mySelectionChanged, s, sjbct), eventsList);
            }

            return chain.Cast<FrameworkElement>();
        }

        /// <summary>
        /// Subscribe PreviewMouseLeftButtonDown on Composite (Border) with a conditional predicate.
        /// </summary>
        /// <param name="chain"></param>
        /// <param name="key"></param>
        /// <param name="deleg"></param>
        /// <param name="peb"></param>
        /// <returns></returns>
        private static FrameworkElement setSingleClick(this FrameworkElement chain, string key, MouseButtonEventHandler deleg, Predicate<Border> peb)
        {
            if (deleg != null && peb != null && peb((Border)chain))
            {
                var mouseSingleClick = Observable.FromEventPattern<MouseButtonEventArgs>(chain.Cast<Border>(), "PreviewMouseLeftButtonDown");

                Action<EventPattern<MouseButtonEventArgs>> actionDelegate = pattern =>
                {
                   if (deleg != null)
                   {
                       if (pattern.EventArgs.ClickCount == 1)
                       {
                           deleg(chain.Cast<Border>(), pattern.EventArgs);
                       }
                   }
                };

                Subject<EventPattern<MouseButtonEventArgs>> sjbct = new Subject<EventPattern<MouseButtonEventArgs>>();
                IObservable<EventPattern<MouseButtonEventArgs>> iobs = sjbct.AsObservable();
                var s = mouseSingleClick.Merge<EventPattern<MouseButtonEventArgs>>(iobs).Subscribe(actionDelegate);

                //Store IDisposable in Dictionary
                Dictionary<string, IDisposable> eventsList = ((Border)chain).GetDisposablesDictionaryFromBorder();
                AddToDisposablesDictionary("SingleClick" + key, new ObservableDisposer(mouseSingleClick, s, sjbct), eventsList);
            }

            return chain.Cast<FrameworkElement>();
        }

        /// <summary>
        /// Subscribe PreviewMouseLeftButtonDown with ClickCount of 2 on Composite (Border) with a conditional predicate.
        /// </summary>
        /// <param name="chain"></param>
        /// <param name="key"></param>
        /// <param name="deleg"></param>
        /// <param name="peb"></param>
        /// <returns></returns>
        private static FrameworkElement setDoubleClick(this FrameworkElement chain, string key, MouseButtonEventHandler deleg, Predicate<Border> peb)
        {
            if (deleg != null && peb != null && peb((Border)chain))
            {
                var mouseDoubleClick = Observable.FromEventPattern<MouseButtonEventArgs>(chain.Cast<Border>(), "PreviewMouseLeftButtonDown");

                Action<EventPattern<MouseButtonEventArgs>> actionDelegate = pattern =>
                {
                    if (deleg != null)
                    {
                        if (pattern.EventArgs.ClickCount == 2)
                        {
                            deleg(chain.Cast<Border>(), pattern.EventArgs);
                        }
                    }
                };

                Subject<EventPattern<MouseButtonEventArgs>> sjbct = new Subject<EventPattern<MouseButtonEventArgs>>();
                IObservable<EventPattern<MouseButtonEventArgs>> iobs = sjbct.AsObservable();
                var s = mouseDoubleClick.Merge<EventPattern<MouseButtonEventArgs>>(iobs).Subscribe(actionDelegate);

                //Store IDisposable in Dictionary
                Dictionary<string, IDisposable> eventsList = ((Border)chain).GetDisposablesDictionaryFromBorder();
                AddToDisposablesDictionary("DoubleClick" + key, new ObservableDisposer(mouseDoubleClick, s, sjbct), eventsList);
            }

            return chain.Cast<FrameworkElement>();
        }

        #endregion

        #endregion
    }//end of class
}//end of namespace
